#!/bin/bash

#TODO: required commands: 'stat grep test declare echo exit return if pwd git'
logfile="/tmp/gitcheck.chmod.log"
lockfile="/tmp/gitcheck.lock"
echo "----- Start `date`" >> "$logfile"
chmod a-rwx,u+rw -- "$logfile"
onint() {
  echo "${0}: Ignored C-c!"
}
trap onint sigint
#FIXME: make onint parse a hashmap of $dir -> $original_attrs  to chmod restore on: EXIT sigint

gitcheck() {
  if test "$#" -ne "1"; then
    echo "too little/many args($#): $@"
    exit 15
  fi
  greptext="$1"
  git status 2>/dev/null |grep -q "$greptext"
  declare -a pipes=("${PIPESTATUS[@]}")
  grepec="${pipes[1]}"
  gitec="${pipes[0]}"
  if test "0$gitec" -ne "0"; then
    echo "Non-zero exit code($gitec) from \"git status '`pwd`'\"" | grep --color=always "Non-zero"
    return 16
    #ec==16 means git status failed, likely not a git repo!
  fi
  if test "$grepec" -ne 0; then
    #ec != 0 (==1) means not changed!
    return 1
  else
    #ec == 0 means changed!
    return 0
  fi
}


_gitcheckinassumedaccessibledir() {
  if test "$#" -ne "2"; then
    echo "too little/many args($#): $@"
    exit 13
  fi
  dir="$1"
  greptext="$2"
  if test ! -d "$dir"; then
    echo "Dir '$dir' is not a dir!"
    return 18
  fi
  if ! test -r "$dir" -a -x "$dir"; then
    echo "Dir '$dir' is not accessible!" | grep --color=always 'not accessible'
    return 22
  fi

  #begin
  pushd "$dir" >/dev/null
  ec="$?"
  if test "$ec" -ne "0"; then
    echo "pushd failed! for '$dir'"
    return $ec
  fi
  if gitcheck "$greptext"; then
    rt=0
  else
    rt=1
  fi
  popd >/dev/null
  ec="$?"
  if test "$ec" -ne "0"; then
    echo "popd failed!"
    return $ec
  fi
  return "$rt"
  #==0 if changed
  #==1 if not changed
}

gitcheckindir() {
  if test "$#" -ne "2"; then
    echo "too little/many args($#): $@"
    exit 13
  fi
  dir="$1"
  greptext="$2"
  if test ! -d "$dir"; then
    echo "Dir '$dir' is not a dir!"
    return 18
  fi
#  set -x
  if ! test -r "$dir" -a -x "$dir"; then
    #attempt to temporarily make accessible
    #decl. local read-only var:
    declare +g -r backupattrs="`stat --format="%a" -- "$dir"`" # eg. 755
    echo "$backupattrs '$dir'" >> "$logfile"
    if test -z "$backupattrs"; then
      echo "stat failed on '$dir'"
      return 19
    fi
    chmod -c u+rx -- "$dir" 2>&1 >> "$logfile"
    local ecc="$?"
#    local faiul=0
    local rt=1
    if test "$ecc" -ne "0"; then
      echo "Dir '$dir' is not accessible and failed to temporarily make it accessible!" | grep --color=always 'not accessible'
#      echo "failed to make accessible dir '$dir'" | grep -i --color=always "fail"
#      faiul=1
      rt=22
##      return 23 #don't return, let it try to restore attrs
    else
      #do work
      _gitcheckinassumedaccessibledir "$dir" "$greptext"
      rt="$?"
      #done
    fi
    #FIXME: restore attrs even if C-c stopped the script! (that's "trap 'cmd' sigint")
    chmod -c "$backupattrs" -- "$dir" 2>&1 >> "$logfile"
    declare +g -r restoredattrs="`stat --format="%a" -- "$dir"`" # eg. 755
    if test -z "$restoredattrs"; then
      echo "'stat' failed on '$dir' or 'stat' command not found"
      return 20
    fi
    if test "$backupattrs" != "$restoredattrs"; then
      echo "Failed to restore dir's attrs! orig:${backupattrs} current:${restoredattrs}" | grep -i --color=always "fail"
    fi
#    set +x
    return "$rt"
  fi
#  set +x

  _gitcheckinassumedaccessibledir "$dir" "$greptext"
#  return "$?" #extranous
  #==0 if changed
  #==1 if not changed
}


git_moo_check() {
  dir="$1"
  greptext="$2"
  explanation="$3"
  if test "$#" -ne "3"; then
    echo "too little/many args($#): $@" | grep --color=always "args"
    exit 18
  fi

  if test -z "$dir"; then
    echo "no dir passed as arg" | grep --color=always "no dir"
    exit 12
  fi
  if test ! -d "$dir"; then
    echo "Passed dir arg '$dir' doesn't exist!" | grep --color=always "doesn't exist"
    return 14
  fi

  if test -z "$greptext"; then
    echo "empty greptext passed" | grep --color=always "empty"
    exit 17
  fi

  gitcheckindir "$dir" "$greptext"
  ec="$?"
  if test "$ec" -eq "0"; then
    echo "git $explanation in dir: '$dir'" | grep --color=always "$explanation" 
#    if test "1${PIPESTATUS[1]}" -eq "10"; then
#      echo "^ ${greptext}." | grep --color=always "${greptext}"
#    fi
  fi
  return "$ec"
}


main() {
#XXX: no spaces in paths here! unless they are within double quotes "" - then it's okay
declare -ar gitdirlist=(
#eg. "/tmp/a b"  #works fine! (assuming it was 'git init'-ed)
#"/tmp/a c" #fails if not git init-ed, but assuming dir exists! but still continues to next dirs
#"/tmp/a d" #fails if dir doesn't exist; but still continues to next dirs
"/home/zazdxscf/gentooskyline"
"/home/zazdxscf/build/1nonpkgs/ArcaneZetaTaliIlium"
"/home/zazdxscf/build/1nonpkgs/dcqs"
"/home/zazdxscf/privaterepos/ticu"
"/home/zazdxscf/build/1nonpkgs/hsts-everywhere-chrome"
"/home/zazdxscf/build/1nonpkgs/rustLearnage"
"/home/zazdxscf/build/1nonpkgs/footab-code"
"/home/zazdxscf/privaterepos/balance"
"/home/zazdxscf/build/1nonpkgs/rust-playpen"
#"/home/zazdxscf/build/1nonpkgs/rust/rust"
)

for i in "${gitdirlist[@]}"; do
#  echo "$i"
  #gitchangedcheck "$i"
#  echo "$?"
  #gitaheadcheck "$i"
  git_moo_check "$i" 'Changes not staged for commit:' "MODified"
  if test "$?" -ne "14" -a "$?" -ne "22"; then
    git_moo_check "$i" "Your branch is ahead of" "unpushed"
    git_moo_check "$i" "Untracked files:" "NEWfiles"
    git_moo_check "$i" "Changes to be committed:" "stageduncommited"
  fi
done

}



(
  set -e
  #locking from, src: http://www.kfirlavi.com/blog/2012/11/06/elegant-locking-of-bash-program/
  #200 is the file descriptor for the lock file - can't use a var, apparently!
  flock --wait 10 --exclusive 200
  set +e
  main
  exit 0
) 200>${lockfile}

#rm -- "$lockfile"


